# Please note: This object-control logic was 
# originally written in C by Nigel Stewart (zpr.c). 
# Here it was only REWRITTEN to Python.

import numpy
from OpenGL.GL import *

_left = 0.0
_right = 0.0
_bottom = 0.0
_top = 0.0

_mouseX = 0
_mouseY = 0
_mouseLeft = False
_mouseMiddle = False
_mouseRight = False

_objectMatrix = numpy.array([[0, 0, 0, 0],\
                             [0, 0, 0, 0],\
                             [0, 0, 0, 0],\
                             [0, 0, 0, 0]], dtype=numpy.float32)
_lightMatrix = numpy.array([[0, 0, 0, 0],\
                            [0, 0, 0, 0],\
                            [0, 0, 0, 0],\
                            [0, 0, 0, 0]], dtype=numpy.float32)
_cameraMatrix = numpy.array([[0, 0, 0, 0],\
                             [0, 0, 0, 0],\
                             [0, 0, 0, 0],\
                             [0, 0, 0, 0]], dtype=numpy.float32)

objectPositionX = 0.0
objectPositionY = 0.0
objectPositionZ = -0.5
objectRotationHeading = 0.0
objectRotationPitch = 0.0

lightRotationHeading = 0.0
lightRotationPitch = 0.0

cameraRotationHeading = 0.0
cameraRotationPitch = 0.0
cameraPositionX = 0.0
cameraPositionY = 0.0
cameraPositionZ = 0.0

BUTTON_UP = 0
BUTTON_DOWN = 1
LEFT_BUTTON = 2
MIDDLE_BUTTON = 3
RIGHT_BUTTON = 4

def updateObjectMatrix():
    global _objectMatrix
    global objectPositionX
    global objectPositionY
    global objectPositionZ
    global objectRotationPitch
    global objectRotationHeading
    
    glPushAttrib(GL_ALL_ATTRIB_BITS)
    glMatrixMode(GL_MODELVIEW)
    glPushMatrix()

    glLoadIdentity()
    glTranslate(objectPositionX, objectPositionY, objectPositionZ)
    glRotate(objectRotationPitch, 1, 0, 0)
    glRotate(objectRotationHeading, 0, 1, 0)
    _objectMatrix = glGetFloat(GL_MODELVIEW_MATRIX)
    
    glPopMatrix()
    glPopAttrib()

def updateLightMatrix():
    global _lightMatrix
    global objectPositionX
    global objectPositionY
    global objectPositionZ
    global lightRotationPitch
    global lightRotationHeading
   
    glPushAttrib(GL_ALL_ATTRIB_BITS);
    glMatrixMode(GL_MODELVIEW);
    glPushMatrix();

    glLoadIdentity()
    glTranslate(objectPositionX, objectPositionY, objectPositionZ)
    glRotate(lightRotationPitch, 1, 0, 0)
    glRotate(lightRotationHeading, 0, 1, 0)
    _lightMatrix = glGetFloat(GL_MODELVIEW_MATRIX)

    glPopMatrix()
    glPopAttrib()     

def updateCameraMatrix():
    global _cameraMatrix
    global cameraRotationPitch
    global cameraRotationHeading
    global cameraPositionX
    global cameraPositionY
    global cameraPositionZ
   
   
    glPushAttrib(GL_ALL_ATTRIB_BITS);
    glMatrixMode(GL_MODELVIEW);
    glPushMatrix();

    glLoadIdentity()
    glRotate(cameraRotationPitch, 1, 0, 0)
    glRotate(cameraRotationHeading, 0, 1, 0)
    glTranslate(cameraPositionX, cameraPositionY, cameraPositionZ)
    _cameraMatrix = glGetFloat(GL_MODELVIEW_MATRIX)

    glPopMatrix()
    glPopAttrib()  

def init(canvas):
    updateObjectMatrix()
    updateLightMatrix()
    updateCameraMatrix()
    canvas.setReshapeFunc(zprReshape)
    canvas.setMouseFunc(zprMouse)
    canvas.setMotionFunc(zprMotion)
    canvas.setKeyboardFunc(zprKey)

def zprGetObjectMatrix():
    global _objectMatrix
    return _objectMatrix

def zprGetLigthMatrix():
    global _lightMatrix
    return _lightMatrix

def zprGetCameraMatrix():
    global _cameraMatrix
    return _cameraMatrix
   
def zprReshape(w, h):
    global _top
    global _bottom
    global _left
    global _right

    _top = 1.0
    _bottom = -1.0
    _left = -float(w) / float(h)
    _right = - _left



def zprMouse(button, state, x, y):
    global _mouseX
    global _mouseY
    global _mouseLeft
    global _mouseMiddle
    global _mouseRight
    _mouseX = x
    _mouseY = y

    if state == BUTTON_UP:
        if button == LEFT_BUTTON:
            _mouseLeft = True
        elif button == MIDDLE_BUTTON:
            _mouseMiddle = True
        else:
            _mouseRight = True
    else:
        if button == LEFT_BUTTON:
            _mouseLeft = False
        elif button == MIDDLE_BUTTON:
            _mouseMiddle = False
        else:
            _mouseRight = False

def zprKey(key, x, y):
    global cameraPositionX
    global cameraPositionY
    global cameraPositionZ
    global _cameraMatrix

    speed = 10.0
    speedX = 0.0
    speedY = 0.0
    speedZ = 0.0

    if key == 'w':
        speedZ = 1.0
    elif key == 's':
        speedZ = -1.0
    elif key == 'q':
        speedY = -1.0
    elif key == 'e':
        speedY = 1.0
    elif key == 'd':
        speedX = -1.0
    elif key == 'a':
        speedX = 1.0

    cameraPositionX += _cameraMatrix[0][0] * speed * speedX
    cameraPositionY += _cameraMatrix[1][0] * speed * speedX
    cameraPositionZ += _cameraMatrix[2][0] * speed * speedX

    cameraPositionX += _cameraMatrix[0][1] * speed * speedY
    cameraPositionY += _cameraMatrix[1][1] * speed * speedY
    cameraPositionZ += _cameraMatrix[2][1] * speed * speedY

    cameraPositionX += _cameraMatrix[0][2] * speed * speedZ
    cameraPositionY += _cameraMatrix[1][2] * speed * speedZ
    cameraPositionZ += _cameraMatrix[2][2] * speed * speedZ

    updateCameraMatrix()

def zprMotion(x, y):
    global _mouseX
    global _mouseY
    global _mouseRight
    global _mouseLeft
    global _mouseMiddle

    global objectPositionX
    global objectPositionY
    global objectPositionZ
    global objectRotationHeading
    global objectRotationPitch

    global lightRotationHeading
    global lightRotationPitch

    global cameraRotationHeading
    global cameraRotationPitch
    global cameraPositionX
    global cameraPositionY
    global cameraPositionZ

    global _cameraMatrix
    global _objectMatrix
    global _lightMatrix

    dx = x - _mouseX
    dy = y - _mouseY

    if dx == 0 and dy == 0:
        return

    objectChanged = False

    if _mouseRight == True:
        objectPositionZ += dy * 0.01
        objectChanged = True
    elif _mouseLeft == True:
        objectRotationHeading += dx * 0.3
        objectRotationPitch += dy * 0.3
        objectChanged = True

    if objectChanged == True:
        updateObjectMatrix()

    lightChanged = False

    if _mouseMiddle == True:
        lightRotationHeading += dx * 0.3
        lightRotationPitch += dy * 0.3
        lightChanged = True

    if objectChanged == True or lightChanged == True:
        updateLightMatrix()

    cameraChanged = False

    if _mouseMiddle == True:
        speed = 0.05
        cameraPositionX += _cameraMatrix[0][0] * speed * -dx
        cameraPositionY += _cameraMatrix[1][0] * speed * -dx
        cameraPositionZ += _cameraMatrix[2][0] * speed * -dx

        cameraPositionX += _cameraMatrix[0][1] * speed * dy
        cameraPositionY += _cameraMatrix[1][1] * speed * dy
        cameraPositionZ += _cameraMatrix[2][1] * speed * dy
        cameraChanged = True
    elif _mouseRight == True:
        speed = 0.05
        cameraPositionX += _cameraMatrix[0][2] * speed * -dy
        cameraPositionY += _cameraMatrix[1][2] * speed * -dy
        cameraPositionZ += _cameraMatrix[2][2] * speed * -dy
        cameraChanged = True
    elif _mouseLeft == True:
        cameraRotationHeading += dx * 0.3
        cameraRotationPitch += dy * 0.3
        cameraChanged = True

    if cameraChanged == True:
        updateCameraMatrix()

    _mouseX = x
    _mouseY = y